using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

namespace FrameworkEditor
{
    public class EmmyLuaTipGenerate
    {
        private const string EmmyLuaDebugEnabled = "EmmyLuaDebugEnabled";
        public static bool isEnabledEmmyLuaDebug;
        private const string EmmyLuaDebugWait = "EmmyLuaDebugWait";
        public static bool isEmmyLuaDebugWait;
        [InitializeOnLoadMethod]
        static void InitializeOnLoad()
        {
            isEnabledEmmyLuaDebug = EditorPrefs.GetBool(EmmyLuaDebugEnabled);
            Menu.SetChecked("SLTools/Lua/是否使用调试功能", isEnabledEmmyLuaDebug);
            isEmmyLuaDebugWait = EditorPrefs.GetBool(EmmyLuaDebugWait);
            Menu.SetChecked("SLTools/Lua/调试功能是否等待连接", isEmmyLuaDebugWait);
        }
        
        // [MenuItem("SLTools/Lua/是否使用调试功能")]
        // private static void SwitchEnableEmmyLuaDebug()
        // {
        //     isEnabledEmmyLuaDebug = !isEnabledEmmyLuaDebug;
        //     EditorPrefs.SetBool(EmmyLuaDebugEnabled, isEnabledEmmyLuaDebug);
        //     Menu.SetChecked("SLTools/Lua/是否使用调试功能", isEnabledEmmyLuaDebug);
        // }
        
        // [MenuItem("SLTools/Lua/调试功能是否等待连接")]
        // private static void SwitchEmmyLuaDebugWait()
        // {
        //     isEmmyLuaDebugWait = !isEmmyLuaDebugWait;
        //     EditorPrefs.SetBool(EmmyLuaDebugWait, isEmmyLuaDebugWait);
        //     Menu.SetChecked("SLTools/Lua/调试功能是否等待连接", isEmmyLuaDebugWait);
        // }
        //
        public static string[] directoryPaths ={
            $"{Application.dataPath}/ZProj/Scripts/Lua",
            $"{Application.dataPath}/slframework/Scripts/Lua/framework",
        };
        public static string[] ignorePathStr =
        {
            "EmmyTypeGenerator",
        };
        /// <summary>
        /// 查找最大行数
        /// </summary>
        public static int maxCheckLineNumber = 100;

        [MenuItem("Assets/Lua/Generate EmmyLua(当前选中目录) 注解")]
        public static void GenerateSelectedDirEmmyLua()
        {
            if (Selection.assetGUIDs.Length > 0)
            {
                var path = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
                if(Directory.Exists(path))
                {
                    Debug.Log("Selected directory: " + path);
                    GenerateEmmyLuaTip(new string[]{path});
                    return;
                }
            }

            Debug.Log("No directory selected.");
        }

        // [MenuItem("SLTools/Lua/Generate EmmyLua 注解")]
        // public static void GenerateEmmyLua()
        // {
        //     //生成EmmyLua注释代码
        //     GenerateEmmyLuaTip(directoryPaths);
        //     //生成PB EmmyLua注释代码
        //     // PbUtils.UpdatePBFromSVN();
        // }

        public static void GenerateEmmyLuaTip(string[] directoryPaths)
        {
            // 指定目录路径
        
            // 获取指定目录下所有Lua文件
            List<string> luaFiles = new List<string>();

            for (int i = 0; i < directoryPaths.Length; i++)
            {
                FileUtils.FindFilesInDirectory(directoryPaths[i], luaFiles, "*.lua");
            }
            
            int totalLines = luaFiles.Count;
            int index = 0;
            foreach (string filePath in luaFiles)
            {
                // 检查文件名是否匹配忽略列表中的任何模式
                bool shouldIgnore = false;
                // 检查文件是否在忽略列表中
                foreach (string str in ignorePathStr)
                {
                    if (filePath.Contains(str))
                    {
                        shouldIgnore = true;
                        break;
                    }
                }
                if (shouldIgnore)
                {
                    index++;
                    continue;
                }
                
                List<string> lines = new List<string>();
                bool hasChanged = false;

                // 读取文件内容
                using (StreamReader reader = new StreamReader(filePath))
                {
                    string content = reader.ReadToEnd();
                
                    // 将文件内容按行分割
                    lines.AddRange(content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None));
                }

                // 移除module
                lines = RemoveModule(lines);
                // class添加注释
                lines = ProcessContentClass(lines, ref hasChanged);
                // pureTable 添加注释
                lines = ProcessContentPureTable(lines, ref hasChanged);
                // table 添加注释
                lines = ProcessContentTable(lines, ref hasChanged);

                lines = ProcessContentRpcOnReceive(filePath, lines, ref hasChanged);
                
                // 将处理后的内容写回到原文件
                if (hasChanged)
                {
                    bool hasTrailingNewLine = lines[lines.Count - 1].EndsWith(Environment.NewLine);
                    using (StreamWriter writer = new StreamWriter(filePath))
                    {
                        for (int i = 0; i < lines.Count; i++)
                        {
                            writer.Write(lines[i]);
                            // 如果是最后一行且没有换行符，不添加换行符
                            if (i < lines.Count - 1 || hasTrailingNewLine)
                            {
                                writer.WriteLine();
                            }
                        }
                    }
                }
                // 计算进度
                float progress = (float)(luaFiles.IndexOf(filePath) + 1) / totalLines;
                EditorUtility.DisplayProgressBar("生成EmmyLuaFile", $"{index}/{totalLines}", progress);
                index++;
            }
            // 完成后清除进度条
            EditorUtility.ClearProgressBar();
            Debug.Log($"All files processed.");
        }
    
        static List<string> tempLines = new List<string>();
        static string classPattern = @"\(([^)]*)\)"; // 匹配括号内的任意字符
        static List<string> ProcessContentClass(List<string> contentLines, ref bool hasChanged)
        {
            string oldContent = "";
            int startIndex = -1;
            string replaceClass  = "MiddleClass";
            int length = Mathf.Min(maxCheckLineNumber, contentLines.Count);
            for (int i = 0; i < length; i++)
            {
                var line = contentLines[i];
                var lastLine = i > 0 ? contentLines[i - 1] : null;
                /// 修正filed拼写错误
                if (!string.IsNullOrEmpty(lastLine) && lastLine.Contains("---@filed"))
                {
                    contentLines[i - 1] = contentLines[i - 1].Replace("---@filed", "---@field");
                    lastLine = contentLines[i - 1];
                }
                
                if (NeedSkip(lastLine))
                {
                    hasChanged = true;
                    break;
                }
                
                if (line.Contains(" class"))
                {
                    hasChanged = true;
                    if (line != null && IsNeedAddTip(lastLine))
                    {
                        oldContent = contentLines[i];
                        startIndex = i;
                        break;
                    }
                }

                if (line.Contains(" FightDataClass"))
                {
                    hasChanged = true;
                    if (line != null && IsNeedAddTip(lastLine))
                    {
                        replaceClass = "FightDataClass";
                        oldContent = contentLines[i];
                        startIndex = i;
                        break;
                    }
                }
            }

            if (oldContent != "")
            {
                string[] names = ExtractToArray(oldContent, classPattern);
                tempLines.Clear();
                switch (names.Length)
                {
                    case 1:
                        tempLines.Add($"---@class {names[0]} : {replaceClass}"); 
                        break;
                    case 2:
                        tempLines.Add($"---@class {names[0]} : {names[1]}");
                        break;
                    default:
                        break;
                }

                if (names.Length > 0)
                {
                    foreach (var line in contentLines)
                    {
                        if (line.Contains($"{names[0]}.instance"))
                        {
                            tempLines.Add($"---@field instance {names[0]}");
                            break;
                        }
                    }
                }
                
                for (int i = 0; i < tempLines.Count; i++)
                {
                    contentLines.Insert(startIndex + i, tempLines[i]);
                }

                hasChanged = true;
            }

            return contentLines;
        }
        
        static string tableattern = @"local\s+(\w+)\s*=\s*[\{_G]";
        /// <summary>
        /// 添加Table注释【主要处理{}/_G】
        /// </summary>
        /// <param name="contentLines"></param>
        /// <returns></returns>
        static List<string> ProcessContentTable(List<string> contentLines,  ref bool hasChanged)
        {
            // 如果已经有变化，直接返回
            if (hasChanged)
                return contentLines;
            
            int length = Mathf.Min(maxCheckLineNumber, contentLines.Count);
            for (int i = 0; i < length; i++)
            {
                var line = contentLines[i];
                var lastLine = i > 0 ? contentLines[i - 1] : null;
                if (NeedSkip(lastLine))
                {
                    hasChanged = true;
                    break;
                }
                if (line != null && ExtractValueBool(line, tableattern) && IsNeedAddTip(lastLine) && 
                    (line.EndsWith("}")|| line.EndsWith("_G")))
                {
                    string name = ExtractValueStr(line, tableattern);
                    contentLines.Insert(i, $"---@class {name}");
                    hasChanged = true;
                    break;
                }
            }
            return contentLines;
        }
        
        static string pureTableKeyword = "pureTable";
        static string _GKeyword = " _M";

        /// <summary>
        /// 添加Table注释
        /// </summary>
        /// <param name="contentLines"></param>
        /// <returns></returns>
        static List<string> ProcessContentPureTable(List<string> contentLines, ref bool hasChanged)
        {
            // 如果已经有变化，直接返回
            if (hasChanged)
                return contentLines;

            for (int i = 0; i < contentLines.Count; i++)
            {
                var line = contentLines[i];
                var lastLine = i > 0 ? contentLines[i - 1] : null;
                
                if (NeedSkip(lastLine))
                {
                    hasChanged = true;
                    break;
                }
                
                int index = line.IndexOf(pureTableKeyword);
                if (index == -1)
                {
                    index = line.IndexOf(_GKeyword);
                }
                if (line != null && IsNeedAddTip(lastLine) && index != -1)
                {
                    int startIndex = line.IndexOf("local ") + "local ".Length;
                    if (startIndex != -1)
                    {
                        string name = line.Substring(startIndex, index - startIndex).Trim();
                        // Remove any trailing characters such as '=' or whitespace
                        name = name.Split(new[] { '=', ' ' }, StringSplitOptions.RemoveEmptyEntries)[0];
                        contentLines.Insert(i, $"---@class {name}");
                        hasChanged = true;
                        break;
                    }
                }
            }
            return contentLines;
        }

        /// <summary>
        /// 处理RPC File 中的OnReceive
        /// </summary>
        /// <param name="contentLines"></param>
        /// <param name="hasChanged"></param>
        static List<string> ProcessContentRpcOnReceive(string filePath, List<string> contentLines, ref bool hasChanged)
        {
            if (filePath.Contains("Rpc."))
            {
                var onReceiveIndexs = new List<int>();
                var onReceiveNames = new List<string>();
                for (int i = 0; i < contentLines.Count; i++)
                {
                    var line = contentLines[i];
                    var lastLine = i > 0 ? contentLines[i - 1] : null;
                    
                    if (lastLine != null && lastLine.Contains("---@param"))
                    {
                        continue;
                    }
                    if (!line.Contains("Rpc:onReceive") || line.Contains("logError") || line.Contains("logWarn") || line.Contains("logNormal"))
                    {
                        continue;
                    }
                    string[] parts = line.Split(new char[] {':', '('}, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Length > 1)
                    {
                        onReceiveIndexs.Add(i);
                        onReceiveNames.Add( parts[1].Substring("onReceive".Length));
                    }
                }

                for (int i = onReceiveIndexs.Count - 1; i >= 0; i--)
                {
                    int index = onReceiveIndexs[i];
                    string name = onReceiveNames[i];
                    contentLines.Insert(index, $"---@param resultCode number");
                    contentLines.Insert(index, $"---@param msg {name}");
                }
            }
            return contentLines;
        }

        /// <summary>
        /// 判断是否匹配
        /// </summary>
        /// <param name="input"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        static bool ExtractValueBool(string input, string pattern)
        {
            Match match = Regex.Match(input, pattern);
            return match.Success;
        }
        
        /// <summary>
        /// 提取local XX = { 或者 local XX = _G的XX
        /// </summary>
        /// <param name="input"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        static string ExtractValueStr(string input, string pattern)
        {
            Match match = Regex.Match(input, pattern);
            if (match.Success)
            {
                return match.Groups[1].Value;
            }
            else
            {
                return string.Empty;
            }
        }
        
        /// <summary>
        /// 判断是否需要添加注释
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        static bool IsNeedAddTip(string input)
        {
            return input == null || (input != null && !input.Contains("---@class")
                                                   && !input.Contains("--@field") && !input.Contains("---@module") 
                                                   && !input.Contains("---@filed"));
        }
        
        static bool NeedSkip(string input)
        {
            return !string.IsNullOrEmpty(input) && (input.Contains("---@class") || input.Contains("---@module"));
        }

        /// <summary>
        /// 提取class(XX)中的内容到数组
        /// </summary>
        /// <param name="input"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        static string[] ExtractToArray(string input, string pattern)
        {
            Match match = Regex.Match(input, pattern);

            if (match.Success)
            {
                string result = match.Groups[1].Value;
                string[] resultArray = result.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < resultArray.Length; i++)
                {
                    resultArray[i] = resultArray[i].Trim().Trim('\"'); // 移除多余的空格和引号
                }
                return resultArray;
            }
            
            return new string[0];
        }
        
        /// <summary>
        /// 提取class(XX)中的内容到数组
        /// </summary>
        /// <param name="input"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        static List<string> RemoveModule(List<string> contentLines)
        {
            bool hasModule = false;
            for (int i = 0; i < contentLines.Count; i++)
            {
                if (contentLines[i].Contains("---@module"))
                {
                    hasModule = true;
                    break;
                }
            }

            if (hasModule)
            {
                int haveClassLine = -1;
                for (int i = contentLines.Count - 1; i >= 0; i--)
                {
                    if (contentLines[i].Contains("class("))
                    {
                        haveClassLine = i;
                    }

                    if (i < haveClassLine && contentLines[i].Contains("---"))
                    {
                        contentLines.RemoveAt(i);
                    }

                    if (contentLines[i].StartsWith("module"))
                    {
                        break;
                    }
                }
            }

            return contentLines;
        }
    }
}